package cn.elwy.rcp.ui.table.provider;

import java.lang.reflect.Array;
import java.util.Collection;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.elwy.rcp.ui.table.adapter.TreeNodeContentAdapter;
import cn.elwy.rcp.ui.util.AdapterUtil;

/**
 * 内容提供者类，支持树、表格、列表等控件
 * @author huangsq
 * @version 1.0, 2015-01-05
 * @since 1.0, 2015-01-05
 */
public class TableTreeContentProvider implements ITreeContentProvider {

  private static final Object[] NO_CHILDREN = new Object[0];
  protected Logger logger = LoggerFactory.getLogger(this.getClass());
  private Viewer viewer;

  @Override
  public Object[] getElements(Object element) {
    Object[] children = getChildren(element);
    if (children.length < 1 && element instanceof Object) {
      return new Object[] { element };
    }
    return children;
  }

  @Override
  public Object[] getChildren(Object element) {
    TreeNodeContentAdapter adapter = AdapterUtil.getAdapter(element, TreeNodeContentAdapter.class);
    if (adapter != null) {
      return adapter.getChildren(element);
    }
    IWorkbenchAdapter adapter1 = AdapterUtil.getAdapter(element, IWorkbenchAdapter.class);
    if (adapter1 != null) {
      return adapter1.getChildren(element);
    }
    if (element instanceof Collection) {
      return ((Collection<?>) element).toArray();
    } else if (element instanceof Object[] || element instanceof Array) {
      return (Object[]) element;
    }
    return NO_CHILDREN;
  }

  @Override
  public Object getParent(Object element) {
    TreeNodeContentAdapter adapter = AdapterUtil.getAdapter(element, TreeNodeContentAdapter.class);
    if (adapter != null) {
      return adapter.getParent(element);
    }
    IWorkbenchAdapter adapter1 = AdapterUtil.getAdapter(element, IWorkbenchAdapter.class);
    if (adapter1 != null) {
      return adapter1.getChildren(element);
    }
    return null;
  }

  @Override
  public boolean hasChildren(Object element) {
    TreeNodeContentAdapter adapter = AdapterUtil.getAdapter(element, TreeNodeContentAdapter.class);
    if (adapter != null) {
      if (adapter.hasChildren(element)) {
        return true;
      }
    }
    // try {
    // if (element instanceof IContainer) {
    // IContainer c = (IContainer) element;
    // if (!c.isAccessible())
    // return false;
    // return c.members().length > 0;
    // }
    // } catch (CoreException ex) {
    // logger.error(ex.getLocalizedMessage(), ex);
    // return false;
    // }
    return getChildren(element).length > 0;
  }

  @Override
  public void dispose() {
    if (viewer != null) {
      /*
       * IWorkspace workspace = null; Object obj = viewer.getInput(); if (obj instanceof IWorkspace) { workspace =
       * (IWorkspace) obj; } else if (obj instanceof IContainer) { workspace = ((IContainer) obj).getWorkspace(); } if
       * (workspace != null) { workspace.removeResourceChangeListener(this); }
       */}
  }

  @Override
  public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    /*
     * this.viewer = viewer; IWorkspace oldWorkspace = null; IWorkspace newWorkspace = null; if (oldInput instanceof
     * IWorkspace) { oldWorkspace = (IWorkspace) oldInput; } else if (oldInput instanceof IContainer) { oldWorkspace =
     * ((IContainer) oldInput).getWorkspace(); } if (newInput instanceof IWorkspace) { newWorkspace = (IWorkspace)
     * newInput; } else if (newInput instanceof IContainer) { newWorkspace = ((IContainer) newInput).getWorkspace(); }
     * if (oldWorkspace != newWorkspace) { if (oldWorkspace != null) { oldWorkspace.removeResourceChangeListener(this);
     * } if (newWorkspace != null) { newWorkspace.addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); } }
     */}

  // public final void resourceChanged(final IResourceChangeEvent event) {
  // processDelta(event.getDelta());
  // }

  // protected void processDelta(IResourceDelta delta) {
  // Control ctrl = viewer.getControl();
  // if (ctrl == null || ctrl.isDisposed()) {
  // return;
  // }
  // final Collection<Runnable> runnables = new ArrayList<Runnable>();
  // processDelta(delta, runnables);
  // if (runnables.isEmpty()) {
  // return;
  // }
  // // Are we in the UIThread? If so spin it until we are done
  // if (ctrl.getDisplay().getThread() == Thread.currentThread()) {
  // runUpdates(runnables);
  // } else {
  // ctrl.getDisplay().asyncExec(new Runnable() {
  // /*
  // * (non-Javadoc)
  // * @see java.lang.Runnable#run()
  // */
  // public void run() {
  // // Abort if this happens after disposes
  // Control ctrl = viewer.getControl();
  // if (ctrl == null || ctrl.isDisposed()) {
  // return;
  // }
  //
  // runUpdates(runnables);
  // }
  // });
  // }
  //
  // }

  /**
   * Run all of the runnables that are the widget updates
   * @param runnables
   */
  // private void runUpdates(Collection<Runnable> runnables) {
  // Iterator<Runnable> runnableIterator = runnables.iterator();
  // while (runnableIterator.hasNext()) {
  // ((Runnable) runnableIterator.next()).run();
  // }
  //
  // }

  /**
   * Process a resource delta. Add any runnables
   */
  // private void processDelta(IResourceDelta delta, Collection<Runnable> runnables) {
  // // he widget may have been destroyed
  // // by the time this is run. Check for this and do nothing if so.
  // Control ctrl = viewer.getControl();
  // if (ctrl == null || ctrl.isDisposed()) {
  // return;
  // }
  //
  // // Get the affected resource
  // final IResource resource = delta.getResource();
  //
  // // If any children have changed type, just do a full refresh of this
  // // parent,
  // // since a simple update on such children won't work,
  // // and trying to map the change to a remove and add is too dicey.
  // // The case is: folder A renamed to existing file B, answering yes to
  // // overwrite B.
  // IResourceDelta[] affectedChildren = delta.getAffectedChildren(IResourceDelta.CHANGED);
  // for (int i = 0; i < affectedChildren.length; i++) {
  // if ((affectedChildren[i].getFlags() & IResourceDelta.TYPE) != 0) {
  // runnables.add(getRefreshRunnable(resource));
  // return;
  // }
  // }
  //
  // // Opening a project just affects icon, but we need to refresh when
  // // a project is closed because if child items have not yet been created
  // // in the tree we still need to update the item's children
  // int changeFlags = delta.getFlags();
  // if ((changeFlags & IResourceDelta.OPEN) != 0) {
  // if (resource.isAccessible()) {
  // runnables.add(getUpdateRunnable(resource));
  // } else {
  // runnables.add(getRefreshRunnable(resource));
  // return;
  // }
  // }
  // // Check the flags for changes the Navigator cares about.
  // // See ResourceLabelProvider for the aspects it cares about.
  // // Notice we don't care about F_CONTENT or F_MARKERS currently.
  // if ((changeFlags & (IResourceDelta.SYNC | IResourceDelta.TYPE | IResourceDelta.DESCRIPTION)) != 0) {
  // runnables.add(getUpdateRunnable(resource));
  // }
  // // Replacing a resource may affect its label and its children
  // if ((changeFlags & IResourceDelta.REPLACED) != 0) {
  // runnables.add(getRefreshRunnable(resource));
  // return;
  // }
  //
  // // Handle changed children .
  // for (int i = 0; i < affectedChildren.length; i++) {
  // processDelta(affectedChildren[i], runnables);
  // }
  //
  // // @issue several problems here:
  // // - should process removals before additions, to avoid multiple equal
  // // elements in viewer
  // // - Kim: processing removals before additions was the indirect cause of
  // // 44081 and its varients
  // // - Nick: no delta should have an add and a remove on the same element,
  // // so processing adds first is probably OK
  // // - using setRedraw will cause extra flashiness
  // // - setRedraw is used even for simple changes
  // // - to avoid seeing a rename in two stages, should turn redraw on/off
  // // around combined removal and addition
  // // - Kim: done, and only in the case of a rename (both remove and add
  // // changes in one delta).
  //
  // IResourceDelta[] addedChildren = delta.getAffectedChildren(IResourceDelta.ADDED);
  // IResourceDelta[] removedChildren = delta.getAffectedChildren(IResourceDelta.REMOVED);
  //
  // if (addedChildren.length == 0 && removedChildren.length == 0) {
  // return;
  // }
  //
  // final Object[] addedObjects;
  // final Object[] removedObjects;
  //
  // // Process additions before removals as to not cause selection
  // // preservation prior to new objects being added
  // // Handle added children. Issue one update for all insertions.
  // int numMovedFrom = 0;
  // int numMovedTo = 0;
  // if (addedChildren.length > 0) {
  // addedObjects = new Object[addedChildren.length];
  // for (int i = 0; i < addedChildren.length; i++) {
  // addedObjects[i] = addedChildren[i].getResource();
  // if ((addedChildren[i].getFlags() & IResourceDelta.MOVED_FROM) != 0) {
  // ++numMovedFrom;
  // }
  // }
  // } else {
  // addedObjects = new Object[0];
  // }
  //
  // // Handle removed children. Issue one update for all removals.
  // if (removedChildren.length > 0) {
  // removedObjects = new Object[removedChildren.length];
  // for (int i = 0; i < removedChildren.length; i++) {
  // removedObjects[i] = removedChildren[i].getResource();
  // if ((removedChildren[i].getFlags() & IResourceDelta.MOVED_TO) != 0) {
  // ++numMovedTo;
  // }
  // }
  // } else {
  // removedObjects = new Object[0];
  // }
  // // heuristic test for items moving within same folder (i.e. renames)
  // final boolean hasRename = numMovedFrom > 0 && numMovedTo > 0;
  //
  // Runnable addAndRemove = new Runnable() {
  // public void run() {
  // if (viewer instanceof AbstractTreeViewer) {
  // AbstractTreeViewer treeViewer = (AbstractTreeViewer) viewer;
  // // Disable redraw until the operation is finished so we don't
  // // get a flash of both the new and old item (in the case of
  // // rename)
  // // Only do this if we're both adding and removing files (the
  // // rename case)
  // if (hasRename) {
  // treeViewer.getControl().setRedraw(false);
  // }
  // try {
  // if (addedObjects.length > 0) {
  // treeViewer.add(resource, addedObjects);
  // }
  // if (removedObjects.length > 0) {
  // treeViewer.remove(removedObjects);
  // }
  // } finally {
  // if (hasRename) {
  // treeViewer.getControl().setRedraw(true);
  // }
  // }
  // } else {
  // ((StructuredViewer) viewer).refresh(resource);
  // }
  // }
  // };
  // runnables.add(addAndRemove);
  // }

  /**
   * Return a runnable for refreshing a resource.
   * @param resource
   * @return Runnable
   */
  // private Runnable getRefreshRunnable(final IResource resource) {
  // return new Runnable() {
  // public void run() {
  // ((StructuredViewer) viewer).refresh(resource);
  // }
  // };
  // }

  /**
   * Return a runnable for refreshing a resource.
   * @param resource
   * @return Runnable
   */
  // private Runnable getUpdateRunnable(final IResource resource) {
  // return new Runnable() {
  // public void run() {
  // ((StructuredViewer) viewer).update(resource, null);
  // }
  // };
  // }

}
